package controller;

import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import model.Model;
import model.ModelFactory;
import session.Session;
import view.View;
import view.ViewFactory;

/**
 * Controller class implements the flow of control between views and their
 * implementation models (instantiation and onvokation) as well as contol of the
 * session and authentication boolean values.
 *
 * @author Reynaldo Gonzales.
 * @version 1.0
 *
 */
public class Controller extends HttpServlet {

    private Model model;
    private View view;
    private String action;
    private HttpServletRequest request;
    private HttpServletResponse response;
    private Session session;

    /**
     * Controller() is the reciever of view information that is passed onto the
     * model that implements the calling view. In particular, it handles the
     * checking of authenticated users and their redirection to their Lithub
     * Dashboard.
     *
     * @param a HttpServletRequest request which holds the HTTP request
     * information of the requesting user view.
     *
     * @param b HttpServletResponse response to the requesting user view.
     *
     */
    public Controller(HttpServletRequest req, HttpServletResponse res) throws IOException {
        new ViewFactory(req, res);

        request = req;
        response = res;

        // Order matters
        if (this.allRequiredVariablesInitialized() // Has the Model, View, and Action been specified?
                && this.inputHasBeenSanitized() // Is everything clean?
                && this.modelAndViewClassesExist() // Do the classes exist?
                && this.tryToInstantiateClasses() // Did we instantiate the models?
                && this.isAuthorized()) // Is the user requesting the information authorized?
        {
        } else {
            HttpSession session = request.getSession(false); // Check session status
            if (session.getAttribute("user") != null) { // If they are logged in, then redirect them to the user page
                model = ModelFactory.createModel(request, "UserPage");
                view = ViewFactory.createView("UserPageHTML");
                action = "ShowUserPage";
            } else { // If they aren't logged in, direct them to the front page
                // Or default to the front page if something failed
                model = ModelFactory.createModel(request, "FrontPage");
                view = ViewFactory.createView("FrontPageHTML");
                action = "displayFrontPage";
            }
        }
    }

    /**
     * invoke causes a model to start executing on a validated action and also
     * casues the view to invoke it's implementing model.
     *
     */
    public void invoke() {
        model.invoke(action);
        view.invoke(model);
    }

    private Boolean allRequiredVariablesInitialized() {
        if (request.getParameter("model") == null
                || request.getParameter("view") == null
                || request.getParameter("action") == null) {
            return false;
        }
        return true;
    }

    private Boolean inputHasBeenSanitized() {
        return true;
    }

    private Boolean modelAndViewClassesExist() {
        return ModelFactory.modelExists(request.getParameter("model"))
                && ViewFactory.viewExists(request.getParameter("view"));
    }

    private Boolean isAuthorized() {
        session = new Session(request); // Create a session with information about the user and their request
        return session.isAuthorized(model, view, action); // Check if the user is authorized
    }

    private Boolean tryToInstantiateClasses() throws IOException {
        model = ModelFactory.createModel(request, request.getParameter("model"));
        view = ViewFactory.createView(request.getParameter("view"));
        action = request.getParameter("action");

        return true;
    }
}
